#pragma once

#include <iostream>
#include "err.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <cerrno>
#include <string>
#include <functional>
#include <unistd.h>
#include <pthread.h>
#include "logMessage.hpp"
#include "ThreadPool.hpp"

namespace ns_tcp
{
    using func_t = std::function<std::string(const std::string &)>;
    static const int backlog = 32;

    class TcpServer;

    class ThreadDate
    {
    public:
        ThreadDate(int sock, std::string clientip, uint16_t port, TcpServer *tcpserver)
            : _sock(sock), _clientip(clientip), _clientport(port), _tcpserver(tcpserver)
        {
        }
        int _sock;
        std::string _clientip;
        uint16_t _clientport;
        TcpServer *_tcpserver;
    };

    class TcpServer
    {
    public:
        TcpServer(func_t func, uint16_t port) : _func(func), _port(port)
        {
        }
        ~TcpServer()
        {
        }

        void initServer()
        {
            // 1 创建socket接口，打开网络文件
            _socklisten = socket(AF_INET, SOCK_STREAM, 0);
            if (_socklisten < 0)
            {
                logMessage(Error, "create socket error");
                exit(SOCKED_ERR);
            }
            logMessage(Info, "create socket success");

            // 2 给服务器指明IP地址和Port
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));

            local.sin_family = AF_INET;
            local.sin_port = htons(_port);      // host to network short
            local.sin_addr.s_addr = INADDR_ANY; // bind本主机任意ip
            if (bind(_socklisten, (sockaddr *)&local, sizeof(local)) < 0)
            {
                logMessage(Error, "bind socket error code:%d info:%s", errno, strerror(errno));
                exit(BIND_ERR);
            }
            logMessage(Info, "bind socket success");

            // 3 监听
            if (listen(_socklisten, backlog) < 0)
            {
                logMessage(Error, "listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(Info, "listen socket success");
        }

        void start()
        {
            while (true)
            {
                struct sockaddr_in client;
                socklen_t len = sizeof(client);

                // 4 获取连接，accept
                int sock = accept(_socklisten, (struct sockaddr *)&client, &len);
                if (sock < 0)
                {
                    logMessage(Warning, "获取连接失败,code:%d,error string:%s", errno, strerror(errno));
                    continue;
                }

                std::string clientip = inet_ntoa(client.sin_addr);
                uint16_t clientport = ntohs(client.sin_port);

                // 5 获取连接成功开始进行业务处理
                logMessage(Info, "获取连接成功:%d from %d,client:%s-%d", sock, _socklisten, clientip.c_str(), clientport);

                // 1 test
                //  service(sock,clientip,clientport);

                // 2 多进程
                //  pid_t id = fork();
                //  if(id < 0)
                //  {
                //      logMessage(Warning,"创建线程失败 code: %d error:%s",errno,strerror(errno));
                //      continue;
                //  }
                //  else if(id == 0)
                //  {
                //      //子进程可以选择关闭不需要的fd
                //      close(_socklisten);
                //      if(fork() > 0) exit(0);

                //     //现在是孙子进程被bash1领养了,不需要等待了
                //     service(sock,clientip,clientport);
                //     exit(0);
                //  }

                // //父进程必须关闭不用的fd防止fd泄露
                // close(sock);

                // 3 源生线程
                // pthread_t tid;
                // ThreadDate *td = new ThreadDate(sock, clientip, clientport, this);
                // pthread_create(&tid, nullptr, threadRoutine, td);


                // 4 线程池版本
                Task t(sock,clientip,clientport,std::bind(&TcpServer::service,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
                ThreadPool<Task>::GetInstance()->pushTask(t);
            }
        }

        // 差点忘记这个地方不能有this指针
        static void *threadRoutine(void *args)
        {
            // 不想回收线程
            pthread_detach(pthread_self());

            ThreadDate *td = static_cast<ThreadDate *>(args);
            td->_tcpserver->service(td->_sock, td->_clientip, td->_clientport);

            delete td;
            return nullptr;
        }

        void service(int sock, std::string clientip, uint16_t port)
        {
            std::string who = clientip + "-" + std::to_string(port);

            char buffer[1024];

            ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] == 0;
                std::string res = _func(buffer);
                logMessage(Info, "%s 发送了一条消息：%s", who.c_str(), res.c_str());
                // std::cout << who << res << std::endl;

                // 处理完消息，返回给对方
                write(sock, res.c_str(), res.size());
            }
            else if (s == 0)
            {
                // 连接被关闭
                logMessage(Warning, "连接已经关闭:%d", sock);
            }
            else
            {
                logMessage(Error, "read Error code:%d info:%s", errno, strerror(errno));
            }
            close(sock);

            // while (true)
            // {
            //     ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
            //     if (s > 0)
            //     {
            //         buffer[s] == 0;
            //         std::string res = _func(buffer);
            //         logMessage(Info, "%s 发送了一条消息：%s", who.c_str(), res.c_str());
            //         // std::cout << who << res << std::endl;

            //         // 处理完消息，返回给对方
            //         write(sock, res.c_str(), res.size());
            //     }
            //     else if (s == 0)
            //     {
            //         // 连接被关闭
            //         close(sock);
            //         logMessage(Warning, "sock已经关闭:%d", sock);
            //         break;
            //     }
            //     else
            //     {
            //         close(sock);
            //         logMessage(Error, "read Error code:%d info:%s", errno, strerror(errno));
            //         break;
            //     }
            // }
        }

    private:
        uint16_t _port;
        func_t _func;
        int _socklisten;
    };
}
